package rita.ui.component;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;

import org.apache.commons.io.FileUtils;

import rita.battle.Batalla;
import rita.settings.HelperEditor;
import rita.settings.Language;
import rita.settings.Settings;
import rita.ui.component.exception.NoEnemiesException;
import rita.widget.SourceCode;

/**
 * Esta clase representa la ventana de di�logo que permite seleccionar mediante checkbox
 * los robots que se enfrentar�n en el campo de batalla.
 * 
 * @author Vanessa Aybar Rosales
 * */
public class DialogSelectEnemies extends CloseableJDialog {
	private static final long serialVersionUID = -3463604350524085848L;

	private static final String pattern = Pattern.quote(System.getProperty("file.separator"));

	private RobotNameClickedEvent robotNameClicked;
	
	private JButton btnOK; 
	
	private JTextField roundsNumberTextField;
	private ImageIcon icon;
	private static Map<String, RobotTemp> mapRobotsTemp=new HashMap<String, RobotTemp>(); 
	
	//private JButton btnInitialPositionsConfig;
	
	private class RobotNameClickedEvent implements ActionListener {
		JButton okButton;
		public RobotNameClickedEvent(JButton disableEnableBtn) {
			okButton = disableEnableBtn;
		}
		int selectionCount = 0;
		@Override
		public void actionPerformed(ActionEvent evt) {			
			if(((JCheckBox)evt.getSource()).isSelected()) {
				++selectionCount;
				if(!okButton.isEnabled()) {
					okButton.setEnabled(true);
				}
			} else {
				 --selectionCount;
				 if(selectionCount==0) {
					 okButton.setEnabled(false);
				 }
			}
		}
		
	}
	
	/**
	 * Create the application.
	 */
	public DialogSelectEnemies()  throws NoEnemiesException {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 * @throws NoEnemiesException 
	 */
	private void initialize() throws NoEnemiesException {
		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		this.getContentPane().setLayout(new BorderLayout(6, 6));
		this.setTitle(Language.get("selectEnemies"));
		
		JLabel label = new JLabel(String.format(Language.get("youtRobotAgainst"),HelperEditor.currentRobotName));
		label.setBorder(new EmptyBorder(12, 12, 0, 12));
		this.getContentPane().add(label, BorderLayout.NORTH);
		label.setIcon(new ImageIcon(DialogSelectEnemies.class.getResource("/images/icons/compite2.png")));
		label.setVerticalAlignment(SwingConstants.TOP);
		label.setFont(label.getFont().deriveFont(Font.BOLD, 14));
		
		JPanel panelRobots = new JPanel();
		panelRobots.setBorder(new EmptyBorder(0, 12, 12, 0));
		this.getContentPane().add(panelRobots, BorderLayout.CENTER);
		panelRobots.setLayout(new BorderLayout(0, 0));
		
		JPanel panelSelectAllNone = new JPanel();
		panelSelectAllNone.setBorder(new EmptyBorder(0, 12, 0, 12));
		panelRobots.add(panelSelectAllNone, BorderLayout.EAST);
		
		GridBagLayout gbl_panelSelectAllNone = new GridBagLayout();
		gbl_panelSelectAllNone.columnWidths = new int[]{0, 0};
		gbl_panelSelectAllNone.rowHeights = new int[] {0, 0, 8};
		gbl_panelSelectAllNone.columnWeights = new double[]{0.0, Double.MIN_VALUE};
		gbl_panelSelectAllNone.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE};
		panelSelectAllNone.setLayout(gbl_panelSelectAllNone);
		
		JButton btnSelectAll = new JButton(Language.get("selectAllEnemies"));
		GridBagConstraints gbc_btnSelectAll = new GridBagConstraints();
		gbc_btnSelectAll.fill = GridBagConstraints.HORIZONTAL;
		gbc_btnSelectAll.insets = new Insets(0, 0, 5, 0);
		gbc_btnSelectAll.gridx = 0;
		gbc_btnSelectAll.gridy = 0;
		panelSelectAllNone.add(btnSelectAll, gbc_btnSelectAll);
		
		JButton btnSelectNone = new JButton(Language.get("selectNoEnemies"));
		GridBagConstraints gbc_btnSelectNone = new GridBagConstraints();
		gbc_btnSelectNone.fill = GridBagConstraints.HORIZONTAL;
		gbc_btnSelectNone.gridx = 0;
		gbc_btnSelectNone.gridy = 1;
		panelSelectAllNone.add(btnSelectNone, gbc_btnSelectNone);
		
		/*
		btnInitialPositionsConfig = new JButton(Language.get("selectRobotsInitialPositions"));
		GridBagConstraints gbc_btnInitialPositionsConfig = new GridBagConstraints();
		gbc_btnSelectNone.fill = GridBagConstraints.HORIZONTAL;
		gbc_btnSelectNone.gridx = 0;
		gbc_btnSelectNone.gridy = 1;
		panelSelectAllNone.add(btnInitialPositionsConfig, gbc_btnInitialPositionsConfig);
		btnInitialPositionsConfig.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				selectRobotsInitialPositions();	
			}
		});
		*/
		
		final JPanel panelSelectRobots = new JPanel();
		panelSelectRobots.setAutoscrolls(true);
		panelRobots.add(panelSelectRobots, BorderLayout.CENTER);
		panelSelectRobots.setLayout(new GridLayout(0, 2));
		
		// Matías
		JPanel panelSelectRoundsNumber = new JPanel();
		panelRobots.add(panelSelectRoundsNumber, BorderLayout.SOUTH);
		panelSelectRoundsNumber.setLayout(new FlowLayout());
		panelSelectRoundsNumber.add(new JLabel(Language.get("selectRoundsNumber")));
		this.roundsNumberTextField = new JTextField(Integer.toString(Batalla.NUMBER_OF_ROUNDS), 5);
		panelSelectRoundsNumber.add(this.roundsNumberTextField);
		
		JPanel panelOkCancel = new JPanel();
		this.getContentPane().add(panelOkCancel, BorderLayout.SOUTH);
		panelOkCancel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 12));
		
		btnOK = new JButton(Language.get("selectStartBattle"));
		btnOK.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				startBattle(panelSelectRobots);
			}
		});
		// comienza deshabilitado hasta que se seleccione 1 enemigo
		//btnOK.setEnabled(false);
		panelOkCancel.add(btnOK);
		
		
		JButton btnCancel = new JButton(Language.get("cancel"));
		btnCancel.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				closeDialog();
			}
		});
		panelOkCancel.add(btnCancel);

		btnSelectAll.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				selectChecks(panelSelectRobots,true);
				//btnOK.setEnabled(true);
			}
		});

		btnSelectNone.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				selectChecks(panelSelectRobots,false);
				//btnOK.setEnabled(false);
			}
		});
		
		// TODO Agregar funcionalidad de elegir las posiciones iniciales de los robots.
		// TODO Averiguar como pasar las posiciones para que se elijan de manera random, probar (0,0,0)
		
		try {
			robotNameClicked = new RobotNameClickedEvent(btnOK);
			addRobotsToPanel(panelSelectRobots);
			this.setResizable(false);
			this.pack();
			PositionCalc.centerDialog(this);
			this.setVisible(true);
		} catch (FileNotFoundException e) {
			throw new NoEnemiesException(e.getMessage());
		}
	}

	/** Recorre el directorio robots y agrega al panel a todos los robots (.class) instalados
	 *  @throws FileNotFoundException si no hay .class en el dir File(Settings.getInstallPath(), "robots")
	 */
	private void addRobotsToPanel(JPanel panel) throws FileNotFoundException {
		if(Settings.getInstallPath()==null) {
			throw new FileNotFoundException("La carpeta de robots no pudo ser encontrara porque InstallPath no esta definido");
		}
		File robotDir =new File(Settings.getInstallPath(),  "robots");
		if(!robotDir.isDirectory() || !robotDir.canRead()) {
			throw new FileNotFoundException("La carpeta de robots "+robotDir+ " no existe o no tiene permisos de lectura");
		}
		boolean robotFound = false;
		// recorrer directorio robots y traer todos los robots instalados
		JCheckBox cb;
		JButton buttonPos;
		icon=new ImageIcon(DialogSelectEnemies.class.getResource("/images/icons/target.jpg"));
		/* buscar recursivametne a todos los .class en InstallPath() + "robots", excluyendo a las inner clases,
		 * porque asumimos que son clases de implementacion. Las reconocemos porque tienen '$' en el nombre de la clase. */
		PosicionRobotAction positionRobotAction; 
		for (File f : FileUtils.listFiles(robotDir, new String[]{"class"}, true)) {
			if (f.getName().endsWith(".class") && f.getName().indexOf('$')==-1) {
				String[] splitPath = f.getParent().split(pattern);
				/* si el path del robot tiene directorio/nombrerobot.class => el nombre del robot es "directorio.nombrerobot",
				   sino es solo "nombrerobot" */
				if(splitPath.length>0) {
					cb = new JCheckBox(splitPath[splitPath.length-1]+"."+f.getName().substring(0,f.getName().lastIndexOf('.')),false);
				} else {
					cb = new JCheckBox(f.getName().substring(0,f.getName().lastIndexOf('.')),false);
				}
				/*
				buttonPos=new JButton(icon);
				buttonPos.addActionListener(new PosicionRobotAction(cb.getText()));
				buttonPos.setSize(30, 30); */
				cb.addActionListener(robotNameClicked);
				panel.add(cb);
				/*
				panel.add(buttonPos);*/
				robotFound = true;
			}
		}
		if(!robotFound) {
			throw new FileNotFoundException("La carpeta de robots no contiene robots");
		}
	}

	protected class RobotTemp{
		String robotName;
		int x;
		int y;
		public RobotTemp(String robotName, int x, int y){
			this.robotName=robotName;
			this.x=x;
			this.y=y;
		}
		public String getRobotName() {
			return robotName;
		}
		public void setRobotName(String robotName) {
			this.robotName = robotName;
		}
		public int getX() {
			return x;
		}
		public void setX(int x) {
			this.x = x;
		}
		public int getY() {
			return y;
		}
		public void setY(int y) {
			this.y = y;
		}
		
	}
	
	private class PosicionRobotAction implements ActionListener{

		RobotTemp robotTemp;
		public PosicionRobotAction(String robotName) {
			if (mapRobotsTemp.get(robotName)==null){
				robotTemp=new RobotTemp(robotName, 0, 0);
				mapRobotsTemp.put(robotName,robotTemp);
			}
		}

		@Override
		public void actionPerformed(ActionEvent arg0) {
			new DialogPositionRobot(robotTemp);
		}
		
		
	}
	
	/** seleccionar o deseleccionar a todos los checkboxes adentro de un panel */
	private void selectChecks(JPanel checks, boolean b) {
		for (Component comp : checks.getComponents()) {
			if (comp instanceof JCheckBox)
				((JCheckBox) comp).setSelected(b);
		}

	}

	/** el usuario selecciono los robots para competir, encontrar cuales selecciono y comenzar la batalla */
	private void startBattle(JPanel checks) {
		Integer roundsNumber;
		try { 
	        roundsNumber = Integer.parseInt(this.roundsNumberTextField.getText()); 
	    } catch(NumberFormatException e) { 
	        roundsNumber = Batalla.NUMBER_OF_ROUNDS; 
	    }
		StringBuilder selectedRobots = new StringBuilder();
		// el robot del usuario siempre participa en la batalla
		selectedRobots.append(Settings.getProperty("defaultpackage")+"."+HelperEditor.currentRobotName);
		selectedRobots.append("*,");
		String robotName;
		// recorrer los checkboxes de los enemigos seleccionados
		for (Component comp : checks.getComponents()) {
			if (comp instanceof JCheckBox && ((JCheckBox) comp).isSelected()){
				robotName=((JCheckBox) comp).getText();
				/* "sample" es el paquete de los que vienen con Robocode;
				* si el robot no es de ese paquete, entonces el nombre debe estar seguido por un asterisco
				*/
				selectedRobots.append(robotName);
				if (robotName.contains("sample.")) {
					selectedRobots.append(',');
				} else { 
					selectedRobots.append("*,");
				}
			}
		}
		HelperEditor.setEnemies(selectedRobots.toString());
		closeDialog();
		SourceCode.callBatalla(Integer.valueOf(roundsNumber));	
	}
}
